﻿

Public Class TerminalDataUploadForm

    Private _pi As ProjectItem
    Private _sts As StartUpTypeService

#Region " 构造函数 "

    Public Sub New()

        ' 此调用是 Windows 窗体设计器所必需的。
        InitializeComponent()

        ' 在 InitializeComponent() 调用之后添加任何初始化。

    End Sub

#End Region

#Region " 界面操作 "

    Private Sub TerminalDataUploadForm_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        Me.CenterToParent()
        Me.btnUpload.Enabled = False
        Me.btnCancel.Enabled = False

        _pi = Me.MyParentForm.PI
        '_pi = New ProjectItem()

        _sts = New StartUpTypeService(_pi)

        _InitStartupList()
        _InitDataGridView()

        LoadData()

    End Sub

    Private Sub TerminalDataUploadForm_FormClosing(ByVal sender As System.Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles MyBase.FormClosing
        If _isModify = True Then
            Select Case msg.ShowYesNoCancel("启停记录已经修改，是否需要保存？")
                Case Windows.Forms.DialogResult.Yes
                    If Save() = True Then
                        msg.Show("保存成功。")
                    Else
                        msg.ShowError("保存失败。")
                    End If

                Case Windows.Forms.DialogResult.Cancel
                    e.Cancel = True

            End Select
        End If

        If _IsUploading = True Then
            msg.Show("正在上传数据，请先取消上传操作。下次上传时，将从当前进度继续上传。")
            e.Cancel = True
        End If
    End Sub

    Private Sub btnUpload_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnUpload.Click

        Me.btnUpload.Enabled = False

        If _isCreate = True Then
            If msg.ShowYesNo("上传数据前，需先保存新的启停纪录。是否保存纪录，并继续上传操作？") = Windows.Forms.DialogResult.Yes Then
                If Save() = True Then

                Else
                    msg.ShowError("保存失败。")
                    Me.btnUpload.Enabled = True
                    Exit Sub
                End If
            Else
                Me.btnUpload.Enabled = True
                Exit Sub
            End If
        End If

        Me.bgUploadData.RunWorkerAsync()

        'Me.btnCancel.Enabled = True '由DoWork工作线程激活

    End Sub

    Private Sub btnCancel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCancel.Click

        Me.btnCancel.Enabled = False

        Me.bgUploadData.CancelAsync()

        'Me.btnUpload.Enabled = True '由RunWorkerCompleted工作线程激活

    End Sub

    Private Sub btnExit_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnExit.Click
        Me.Close()
    End Sub

#End Region

#Region " 启停记录 "

    Private _netid As Byte = g_netID '网络标识

    Private Const _Startup_Offset As UShort = 17000     '启停纪录起始地址
    Private Const _Startup_Length As UShort = 170       '启停纪录每个数据字节数
    Private Const _Startup_Intval As UShort = 200       '启停纪录总间隔字节数
    Private Const _Startup_Count As UShort = 6          '启停纪录最大数量

    Private Const _AddressInfo_Length As UShort = 30    '每个运输地址信息数据的字节数
    Private Const STARTUP_MAX_COUNT As Integer = 6      '终端最大启停记录数
    Private _Encoding As System.Text.Encoding = System.Text.Encoding.GetEncoding(936) '启停纪录地址信息编码格式; gb2312

    Private _Null_fColor As Color = SystemColors.GrayText
    Private _NotUpload_fColor As Color = SystemColors.WindowText
    Private _Uploading_fColor As Color = SystemColors.WindowText
    Private _Finished_fColor As Color = SystemColors.WindowText

    Private _Null_bColor As Color = Color.LightGray
    Private _NotUpload_bColor As Color = Nothing
    Private _Uploading_bColor As Color = Color.LemonChiffon
    Private _Finished_bColor As Color = Color.PaleGreen

    Private _StartupList As IList(Of StartUpTypeItem4DU) = New List(Of StartUpTypeItem4DU) '启停纪录列表

    '初始化启停纪录表格
    Private Sub _InitStartupList()
        For i As Integer = 0 To STARTUP_MAX_COUNT - 1
            Dim sti As New StartUpTypeItem4DU()
            sti.Index = i
            sti.SeqNo = i + 1
            _StartupList.Add(sti)
        Next
        Me.bsStartup.DataSource = _StartupList
    End Sub

    '初始化启停表格状态
    Private Sub _InitDataGridView()
        For Each row As DataGridViewRow In Me.dgvStartup.Rows
            If row.Cells("dBeginTime").Value = DateTime.MinValue Then
                row.ReadOnly = True
                row.DefaultCellStyle.ForeColor = _Null_fColor
                row.DefaultCellStyle.BackColor = _Null_bColor
                row.Cells("dCheck").ToolTipText = "选择上传"
                row.Cells("dStatus").ToolTipText = "尚无纪录"
            Else
                row.ReadOnly = False
            End If
        Next
    End Sub

    '读取启停数据
    Private Sub LoadData()
        Dim thread As New Threading.Thread(AddressOf _LoadData)
        thread.IsBackground = True
        thread.Start()
    End Sub
    Private Sub _LoadData()

        If _ReadStartup() = True Then
            '_CheckLocalStartup(_StartupList) 'None: 在读取终端启停纪录时做了。
            SetUploadButtonEnabled(True)
        End If

        'For i As Integer = 5 To 0 Step -1
        '    _StartupList(i).BeginTime = Now.AddHours(-i * 2)
        '    _StartupList(i).EndTime = Now.AddHours(-i)
        'Next
        '_CheckLocalStartup(_StartupList)

    End Sub

    '从终端读取启停纪录
    Private Function _ReadStartup() As Boolean

        Dim dt As DateTime
        Dim int As Short
        Dim txt As String
        Dim bufByte() As Byte
        Dim sti As StartUpTypeItem4DU

        Dim lIL As IList(Of StartUpTypeItem)
        Dim lSTI As StartUpTypeItem

        For i As Integer = 0 To _StartupList.Count - 1

            sti = _StartupList(i)

            '读取一条启停纪录
            bufByte = COMHelper.Instance.Send4Byte(_netid, FunctionCode.StartupRead, _Startup_Offset + (i * _Startup_Intval), _Startup_Length / 2) '功能码:42,数据长度:2Byte单位
            If bufByte Is Nothing OrElse bufByte.Length < _Startup_Length Then
                GoTo ErrorHandler
            End If
            If UtilityClass.BufferIsValidate(bufByte, 0, 6) = False Then '检查启停纪录是否有效
                sti.IsLoadTerminalData = False
                Continue For
                'Return True
            Else
                sti.IsLoadTerminalData = True
            End If

            '启动时间
            dt = NumericConvert.Bytes2DateTime(bufByte, 0)
            sti.BeginTime = dt

            '停止时间
            dt = NumericConvert.Bytes2DateTime(bufByte, 6)
            sti.EndTime = dt

            '检查启停纪录是否停止
            If sti.EndTime = Nothing Then
                sti.IsStopRecord = False
                sti.UploadStatus = StartUploadStatus.NotStop
                DataGridView_Row_UpdataState(i, StartUploadStatus.NotStop, CheckState.Unchecked, True)
            Else
                '检查启停纪录是否正常
                If sti.BeginTime > sti.EndTime Then
                    sti.IsLoadTerminalData = False
                    'sti.IsError = True
                    sti.UploadStatus = StartUploadStatus.Error
                    DataGridView_Row_UpdataState(i, StartUploadStatus.Error, CheckState.Unchecked, True)
                    Continue For
                End If
            End If

            '存储页地址
            int = NumericConvert.Byte2Short(bufByte(13), bufByte(12))
            sti.PageIndex = int

            '存储页数
            int = NumericConvert.Byte2Short(bufByte(15), bufByte(14))
            sti.PageCount = int

            '纪录间隔
            int = NumericConvert.Byte2Short(bufByte(17), bufByte(16))
            sti.RecordInterval = int

            '出发地
            txt = _Encoding.GetString(bufByte, 18, _AddressInfo_Length)
            sti.BeginAddress = txt

            '目的地
            txt = _Encoding.GetString(bufByte, 48, _AddressInfo_Length)
            sti.EndAddress = txt

            '发货人
            txt = _Encoding.GetString(bufByte, 78, _AddressInfo_Length)
            sti.Shipper = txt

            '承运人
            txt = _Encoding.GetString(bufByte, 108, _AddressInfo_Length)
            sti.Carrier = txt

            '收货人
            txt = _Encoding.GetString(bufByte, 138, _AddressInfo_Length)
            sti.Receiver = txt

            '检测本地库中是否有该时间启停纪录
            If sti.IsLoadTerminalData = True Then
                lIL = _sts.GetStartUpGroupList(sti.BeginTime.AddSeconds(-1), sti.EndTime.AddSeconds(1), False) '防止传入Nothing: AddSeconds(1)
                If lIL IsNot Nothing AndAlso lIL.Count > 0 Then
                    '本地库已有纪录
                    lSTI = lIL(0)

                    sti.IsLoadLocalData = True
                    sti.ID = lSTI.ID
                    sti.NetID = lSTI.NetID
                    'tSTI.BeginAddress = lSTI.BeginAddress 'begin:使用本地库信息覆盖终端信息 TODO
                    'tSTI.EndAddress = lSTI.EndAddress
                    'tSTI.BeginTime = lSTI.BeginTime
                    'tSTI.EndTime = lSTI.EndTime
                    'tSTI.Shipper = lSTI.Shipper
                    'tSTI.Carrier = lSTI.Carrier
                    'tSTI.Receiver = lSTI.Receiver 'end
                    sti.UploadStatus = lSTI.UploadStatus
                    sti.LastPageIndex = lSTI.LastPageIndex
                    sti.LastPageType = lSTI.LastPageType
                    sti.LastRecordTime = lSTI.LastRecordTime

                    _sts.FillStartUpTypeItem(Of StartUpTypeItem4DU, StartUpDetailTypeItem4DU)(sti) '填充详细启停纪录

                    DataGridView_Row_UpdataState(i, lSTI.UploadStatus)
                Else
                    '本地库无纪录(New)
                    sti.IsNewStartup = True
                    sti.NetID = _netid
                    'If sti.IsStopRecord = True AndAlso sti.IsError = False Then
                    If sti.IsStopRecord = True Then
                        DataGridView_Row_UpdataState(i, StartUploadStatus.NotUpload)
                        _isCreate = True
                    End If
                '_isModify = True '发现新启停纪录，暂不视为用户修改
                End If
            End If

        Next i

        Return True

ErrorHandler:
        'msg.ShowError(g_strReadError)
        Return False

    End Function

    '检测本地库中启停纪录(未上传)
    Private Sub _CheckLocalStartup(ByVal list As IList(Of StartUpTypeItem4DU))

        Dim tSTI As StartUpTypeItem4DU
        Dim lSTI As StartUpTypeItem
        Dim lIL As IList(Of StartUpTypeItem)

        For i As Integer = 0 To list.Count - 1

            tSTI = list(i)

            If tSTI.IsLoadTerminalData = False Then Continue For '未从终端读取到启停纪录

            lIL = _sts.GetStartUpGroupList(tSTI.BeginTime, tSTI.EndTime, False)
            If lIL IsNot Nothing AndAlso lIL.Count > 0 Then
                '本地库已有纪录
                lSTI = lIL(0)

                tSTI.IsLoadLocalData = True
                tSTI.ID = lSTI.ID
                tSTI.NetID = lSTI.NetID
                'tSTI.BeginAddress = lSTI.BeginAddress 'begin:使用本地库信息覆盖终端信息 TODO
                'tSTI.EndAddress = lSTI.EndAddress
                'tSTI.BeginTime = lSTI.BeginTime
                'tSTI.EndTime = lSTI.EndTime
                'tSTI.Shipper = lSTI.Shipper
                'tSTI.Carrier = lSTI.Carrier
                'tSTI.Receiver = lSTI.Receiver 'end
                tSTI.UploadStatus = lSTI.UploadStatus
                tSTI.LastPageIndex = lSTI.LastPageIndex
                tSTI.LastPageType = lSTI.LastPageType
                tSTI.LastRecordTime = lSTI.LastRecordTime

                _sts.FillStartUpTypeItem(Of StartUpTypeItem4DU, StartUpDetailTypeItem4DU)(tSTI) '填充详细启停纪录

                DataGridView_Row_UpdataState(i, lSTI.UploadStatus)
            Else
                '本地库无纪录(New)
                tSTI.IsNewStartup = True
                tSTI.NetID = _netid
                DataGridView_Row_UpdataState(i, StartUploadStatus.NotUpload)
                '_isModify = True '发现新启停纪录，暂不视为用户修改
                _isCreate = True
            End If

        Next i

    End Sub

#Region " 消息处理 "

    Private Sub dgvStartup_DoubleClick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles dgvStartup.DoubleClick

        Detail()

    End Sub

#End Region

#Region " 线程安全 "

    '根据启停纪录上传状态刷新行风格
    Private Sub DataGridView_Row_UpdataState(ByVal rowIndex As Integer, ByVal state As StartUploadStatus)
        DataGridView_Row_UpdataState(rowIndex, state, True, Nothing, Nothing)
    End Sub
    Private Sub DataGridView_Row_UpdataState(ByVal rowIndex As Integer, ByVal state As StartUploadStatus, ByVal isChecked As CheckState, ByVal isReadOnly As Boolean)
        DataGridView_Row_UpdataState(rowIndex, state, False, isChecked, isReadOnly)
    End Sub
    Private Sub DataGridView_Row_UpdataState(ByVal rowIndex As Integer, ByVal state As StartUploadStatus, ByVal isAuto As Boolean, ByVal isChecked As CheckState, ByVal isReadOnly As Boolean)
        Dim obj(4) As Object
        obj(0) = rowIndex
        obj(1) = state
        obj(2) = isChecked
        obj(3) = isReadOnly
        obj(4) = isAuto     '当第一次加载上传状态时，自动设置行状态

        If Me.InvokeRequired Then
            Me.Invoke(New Action(Of Object)(AddressOf _DataGridView_Row_UpdataState), CType(obj, Object))
        Else
            _DataGridView_Row_UpdataState(CType(obj, Object))
        End If
    End Sub
    Private Sub _DataGridView_Row_UpdataState(ByVal obj As Object)
        Dim rowIndex As Integer = obj(0)
        Dim state As StartUploadStatus = obj(1)
        Dim isChecked As CheckState = obj(2)
        Dim isReadOnly As Boolean = obj(3)
        Dim isAuto As Boolean = obj(4)

        If rowIndex < Me.dgvStartup.Rows.Count Then
            Dim row As DataGridViewRow
            row = Me.dgvStartup.Rows(rowIndex)
            Dim sti As StartUpTypeItem4DU
            sti = _StartupList(rowIndex)

            If row IsNot Nothing AndAlso sti IsNot Nothing Then
                Select Case state
                    Case StartUploadStatus.NotUpload
                        row.ReadOnly = IIf(isAuto, False, isReadOnly) 'False
                        row.DefaultCellStyle.ForeColor = _NotUpload_fColor
                        row.DefaultCellStyle.BackColor = _NotUpload_bColor
                        row.Cells("dStatus").Value = My.Resources.Unknow2
                        row.Cells("dStatus").ToolTipText = "尚未上传"
                        row.Cells("dCheck").Value = IIf(isAuto, CheckState.Unchecked, isChecked)
                        ReportChildProgress(0, rowIndex)

                    Case StartUploadStatus.NotFinished
                        row.ReadOnly = IIf(isAuto, False, isReadOnly) 'False
                        row.DefaultCellStyle.ForeColor = _Uploading_fColor
                        row.DefaultCellStyle.BackColor = _NotUpload_bColor '_Uploading_bColor
                        row.Cells("dStatus").Value = My.Resources.Pause
                        row.Cells("dStatus").ToolTipText = "上传未完"
                        row.Cells("dCheck").Value = IIf(isAuto, CheckState.Unchecked, isChecked)
                        ReportChildProgress(CountProgressValue(sti), rowIndex)

                    Case StartUploadStatus.Uploading
                        row.ReadOnly = IIf(isAuto, False, isReadOnly) 'False
                        row.DefaultCellStyle.ForeColor = _Uploading_fColor
                        row.DefaultCellStyle.BackColor = _NotUpload_bColor '_Uploading_bColor
                        row.Cells("dStatus").Value = My.Resources.Upload
                        row.Cells("dStatus").ToolTipText = "正在上传"
                        row.Cells("dCheck").Value = IIf(isAuto, CheckState.Unchecked, isChecked)
                        ReportChildProgress(CountProgressValue(sti), rowIndex)

                    Case StartUploadStatus.Finished
                        row.ReadOnly = IIf(isAuto, True, isReadOnly) 'True
                        row.DefaultCellStyle.ForeColor = _Finished_fColor
                        row.DefaultCellStyle.BackColor = _NotUpload_bColor '_Finished_bColor
                        row.Cells("dStatus").Value = My.Resources.Finish
                        row.Cells("dStatus").ToolTipText = "上传完成"
                        row.Cells("dCheck").Value = IIf(isAuto, CheckState.Unchecked, isChecked)
                        ReportChildProgress(100, rowIndex)

                    Case StartUploadStatus.[UploadError]
                        row.ReadOnly = IIf(isAuto, False, isReadOnly) 'False
                        row.DefaultCellStyle.ForeColor = _Uploading_fColor
                        row.DefaultCellStyle.BackColor = _NotUpload_bColor
                        row.Cells("dStatus").Value = My.Resources.Error1
                        row.Cells("dStatus").ToolTipText = "上传错误"
                        row.Cells("dCheck").Value = IIf(isAuto, CheckState.Unchecked, isChecked)
                        ReportChildProgress(CountProgressValue(sti), rowIndex)

                    Case StartUploadStatus.Error
                        row.ReadOnly = IIf(isAuto, True, isReadOnly) 'True
                        row.DefaultCellStyle.ForeColor = _Uploading_fColor
                        row.DefaultCellStyle.BackColor = _NotUpload_bColor
                        row.Cells("dStatus").Value = My.Resources.Error1
                        row.Cells("dStatus").ToolTipText = "错误记录"
                        row.Cells("dCheck").Value = IIf(isAuto, CheckState.Unchecked, isChecked)
                        ReportChildProgress(0, rowIndex)

                    Case StartUploadStatus.NotStop
                        row.ReadOnly = IIf(isAuto, False, isReadOnly) 'False
                        row.DefaultCellStyle.ForeColor = _Uploading_fColor
                        row.DefaultCellStyle.BackColor = _NotUpload_bColor
                        row.Cells("dStatus").Value = My.Resources.Unknow1
                        row.Cells("dStatus").ToolTipText = "尚未停止"
                        row.Cells("dCheck").Value = IIf(isAuto, CheckState.Unchecked, isChecked)
                        ReportChildProgress(0, rowIndex)

                End Select
            End If
        End If
    End Sub

#End Region

#End Region

#Region " 数据上传 "

    Private _IsUploading As Boolean '是否正在上传标志
    Private _CheckedCurrent As Integer '当前正在上传的选择纪录编号
    Private _CheckedCount As Integer '启停纪录选择计数
    Private _CurrentPageCount As Integer
    Private _TotalPageCount As Integer '当前总共要上传的页数
    Private Const UPLOAD_BASETIME As Decimal = 470619.625 '上传每条数据所需时间Ticks

    Private Const _HData_HalfUp_Count As UShort = 8     '上传数据上半页数据行数
    Private Const _HData_HalfDown_Count As UShort = 8   '上传数据下半页数据行数
    Private Const _HData_Length As UShort = 31          '上传数据每行数据字节数

    Private Sub bgUploadData_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bgUploadData.DoWork

        SetCancelButtonEnabled(True)
        UploadData(e)

    End Sub

    Private Sub bgUploadData_ProgressChanged(ByVal sender As System.Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles bgUploadData.ProgressChanged

        ReportProgress(e)

    End Sub

    Private Sub bgUploadData_RunWorkerCompleted(ByVal sender As System.Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles bgUploadData.RunWorkerCompleted

        UploadCompleted(e.Result, e.Result.IsCanceled)
        SetUploadButtonEnabled(True)

    End Sub

    '上传所有选定纪录的数据
    Private Sub UploadData(ByVal e As System.ComponentModel.DoWorkEventArgs)

        Dim result As DataUploadResult
        Dim sti As StartUpTypeItem4DU
        'Dim sdti As StartUpDetailTypeItem4DU
        e.Result = New DataUploadResult()
        result = e.Result

        ''更新启停纪录表(使用保存按钮)
        'For i As Integer = 0 To _StartupList.Count - 1
        '    sti = _StartupList(i)

        '    '插入新启停纪录; (默认不管是否构选，都上传启停纪录)
        '    If sti.IsNewStartup = True Then
        '        _sts.InsertStartUpTypeItem(sti) '加入新启停记录时，会获取其ID
        '    End If

        '    '更新详细启停纪录; 判断是否已经读取终端启停纪录
        '    If sti.IsLoadTerminalData = True Then
        '        Dim sdts As New StartUpDetailTypeService(_pi, sti)
        '        sdts.UpdateStartUpDetailGroupList(Of StartUpDetailTypeItem4DU)(sti.DetailItemList)
        '    End If
        'Next i

        '检查是否构选上传
        _CheckedCurrent = -1 : _CheckedCount = 0 : _CurrentPageCount = 0
        result.IsChecked = CheckChecked()
        If result.IsChecked = False Then
            Exit Sub
        End If

        _IsUploading = True

        '上传数据至表
        For i As Integer = 0 To _StartupList.Count - 1
            sti = _StartupList(i)
            result.CurrentStartup = sti
            result.CurrentRowIndex = i

            '上传数据
            If sti.CheckState <> CheckState.Unchecked Then

                _CheckedCurrent += 1

                Select Case sti.UploadStatus
                    Case StartUploadStatus.NotUpload
                        If sti.PageCount > 0 Then '终端启停纪录PageCount > 0表示有历史数据
                            result.CurrentPageIndex = sti.PageIndex
                            result.CurrentPageCount = sti.PageCount

                            DataGridView_Row_UpdataState(i, StartUploadStatus.Uploading, True, True)

                            If _DataUpload(sti.PageIndex, sti.PageCount, StartUploadPageType.HalfUp, sti, e) = False Then
                                '上传失败
                                result.IsCompleted = False
                                If result.IsCanceled = True Then '用户取消
                                    DataGridView_Row_UpdataState(i, StartUploadStatus.NotFinished, False, False)
                                    Exit For
                                Else
                                    '上传错误
                                    sti.UploadStatus = StartUploadStatus.[UploadError]
                                    _sts.UpdateStartUpTypeItem(sti.ID, sti.UploadStatus, sti.LastRecordTime, sti.LastPageIndex, sti.LastPageType)

                                    DataGridView_Row_UpdataState(i, StartUploadStatus.[UploadError], False, False)
                                End If
                            Else
                                '上传成功
                                result.IsCompleted = True
                            End If
                        Else
                            result.IsCompleted = True
                        End If
                        If result.IsCompleted = True Then
                            '纪录该启停纪录数据上传状态
                            sti.UploadStatus = StartUploadStatus.Finished
                            _sts.UpdateStartUpTypeItem(sti.ID, sti.UploadStatus, sti.LastRecordTime, sti.LastPageIndex, sti.LastPageType)

                            DataGridView_Row_UpdataState(i, StartUploadStatus.Finished, False, True)
                        End If
                        ReportTotalSpareTime(0)

                    Case StartUploadStatus.NotFinished, StartUploadStatus.Uploading, StartUploadStatus.[UploadError]
                        If sti.PageCount > 0 Then '终端启停纪录PageCount > 0表示有历史数据
                            result.CurrentPageIndex = sti.LastPageIndex
                            result.CurrentPageCount = sti.PageCount - Math.Abs(sti.LastPageIndex - sti.PageIndex)

                            DataGridView_Row_UpdataState(i, StartUploadStatus.Uploading, True, True)

                            If _DataUpload(sti.LastPageIndex, sti.PageCount - Math.Abs(sti.LastPageIndex - sti.PageIndex), sti.LastPageType, sti, e) = False Then
                                '上传失败
                                result.IsCompleted = False
                                If result.IsCanceled = True Then '用户取消
                                    DataGridView_Row_UpdataState(i, StartUploadStatus.NotFinished, False, False)
                                    Exit For
                                Else
                                    '上传错误
                                    sti.UploadStatus = StartUploadStatus.[UploadError]
                                    _sts.UpdateStartUpTypeItem(sti.ID, sti.UploadStatus, sti.LastRecordTime, sti.LastPageIndex, sti.LastPageType)

                                    DataGridView_Row_UpdataState(i, StartUploadStatus.[UploadError], False, False)
                                End If
                            Else
                                '上传成功
                                result.IsCompleted = True
                            End If
                        Else
                            result.IsCompleted = True
                        End If
                        If result.IsCompleted = True Then
                            '纪录该启停纪录数据上传状态
                            sti.UploadStatus = StartUploadStatus.Finished
                            _sts.UpdateStartUpTypeItem(sti.ID, sti.UploadStatus, sti.LastRecordTime, sti.LastPageIndex, sti.LastPageType)

                            DataGridView_Row_UpdataState(i, StartUploadStatus.Finished, False, True)
                        End If
                        ReportTotalSpareTime(0)

                    Case StartUploadStatus.Finished
                        Continue For

                End Select

                '暂时不根据详细启停纪录上传数据
                'For j As Integer = 0 To sti.DetailItemList.Count - 1
                '    sdti = sti.DetailItemList(i)

                '    If sdti.CheckState = CheckState.Checked Then

                '    Else
                '        Continue For
                '    End If
                'Next j

            End If

        Next i

        _IsUploading = False

    End Sub

    '进度报告控件消息处理
    Private Sub ReportProgress(ByVal e As System.ComponentModel.ProgressChangedEventArgs)

        Me.pbDataUpload.Value = e.ProgressPercentage

    End Sub

    '完成上传处理
    Private Sub UploadCompleted(ByVal result As DataUploadResult, ByVal isCancelled As Boolean)

        If result.IsChecked = False Then
            SetUploadCompleted("未选择上传纪录。")
            Exit Sub
        End If

        If isCancelled = True Then
            SetUploadCompleted("已取消数据上传。下次上传时，将从当前进度继续上传。")
            'DataGridView_Row_UpdataState(result.CurrentRowIndex, StartUploadStatus.NotFinished, False, False)
            Exit Sub
        End If

        If result.IsCompleted = True Then
            SetUploadCompleted("已完成数据上传。")
        Else
            SetUploadCompleted("数据上传失败。")
        End If

    End Sub

    '上传某启停纪录的所有页数据
    Private Function _DataUpload(ByVal PageIndex As UShort, ByVal PageCount As UShort, ByVal StartPageType As StartUploadPageType, ByVal sti As StartUpTypeItem4DU, ByVal e As System.ComponentModel.DoWorkEventArgs) As Boolean
        Dim result As DataUploadResult = e.Result
        'Dim bytes() As Byte
        'Dim hDataCount As UShort
        'Dim byteSingle(3) As Byte
        Dim hdts As New HDataTypeService(_pi)

        '将当前启停纪录上传进度置0
        'ReportProgress(0, sti.Index, _CheckedCurrent)

        Dim timeBase As Decimal
        Dim timer As New HighResolutionTimer()
        timer.Start()

        For i As Integer = 0 To PageCount - 1

            '纪录该启停纪录数据上传状态
            sti.LastPageIndex = PageIndex + i '在_HalfPageUpload函数中，也有记录最新上传页索引
            sti.LastPageType = StartPageType
            sti.UploadStatus = StartUploadStatus.NotFinished
            _sts.UpdateStartUpTypeItem(sti.ID, sti.UploadStatus, sti.LastRecordTime, sti.LastPageIndex, sti.LastPageType)

            '取消上传
            If Me.bgUploadData.CancellationPending = True Then
                result.IsCanceled = True
                Return False
            End If

            '上传数据
            If StartPageType = StartUploadPageType.HalfUp Then
                If _HalfPageUpload(PageIndex + i, StartUploadPageType.HalfUp, sti, hdts, e) = False Then
                    Return False
                End If

                StartPageType = StartUploadPageType.HalfDown '上半页完成，置StartPageType为下半页
                sti.LastPageType = StartPageType
                _sts.UpdateStartUpTypeItem(sti.ID, sti.UploadStatus, sti.LastRecordTime, sti.LastPageIndex, sti.LastPageType)

                If _HalfPageUpload(PageIndex + i, StartUploadPageType.HalfDown, sti, hdts, e) = False Then
                    Return False
                End If

                StartPageType = StartUploadPageType.HalfUp '下半页完成，置StartPageType为上半页

            Else
                If _HalfPageUpload(PageIndex + i, StartUploadPageType.HalfDown, sti, hdts, e) = False Then
                    Return False
                End If

                StartPageType = StartUploadPageType.HalfUp '下半页完成，置StartPageType为上半页

            End If

            'ReportProgress(sti.LastPageIndex / sti.PageCount * 100) '报告进度: 精确到页数
            _CurrentPageCount += 1

        Next i

        timer.Stop()
        timeBase = PageCount / timer.ElapsedTime
        Debug.WriteLine(String.Format("===== 上传时间基数: {0}", timeBase))

        '修正当前启停上传进度至100
        ReportProgress(100, sti.Index, _CheckedCurrent, -1, Nothing)

        Return True
    End Function

    '上传半页数据
    Private Function _HalfPageUpload(ByVal PageIndex As UShort, ByVal PageType As StartUploadPageType, ByVal sti As StartUpTypeItem4DU, ByVal hdts As HDataTypeService, ByVal e As System.ComponentModel.DoWorkEventArgs) As Boolean
        Dim result As DataUploadResult = e.Result
        Dim bytes() As Byte
        Dim hDataCount As UShort
        Dim byteSingle(3) As Byte

        bytes = COMHelper.Instance.Send4Byte(_netid, FunctionCode.HistoryByteRead, PageIndex, PageType)
        If bytes Is Nothing Then
            Return False
        End If

        If PageType = StartUploadPageType.HalfUp Then
            hDataCount = _HData_HalfUp_Count
        Else
            hDataCount = _HData_HalfDown_Count
        End If

        result.CurrentPageType = PageType

        '保存当前半页数据
        For j As Integer = 0 To hDataCount - 1

            '取消上传
            If Me.bgUploadData.CancellationPending = True Then
                result.IsCanceled = True
                Return False
            End If

            Dim curOffset As UShort = j * _HData_Length

            If UtilityClass.BufferIsValidate(bytes, curOffset, _HData_Length) = True Then '验证该行数据纪录是否有效

                Dim hdti As New HDataTypeItem()
                hdti.ParentID = sti.ID
                hdti.NetID = 1 '暂时为1号设备

                hdti.RecordTime = NumericConvert.Bytes2DateTime(bytes, curOffset)

                '检测当前半页中，比较数据纪录时间与之前上传最新纪录时间，从之前未完成处开始保存数据。(此处还可做1/2号设备数据互补检测)
                If hdti.RecordTime <= sti.LastRecordTime Then
                    '报告进度: 精确到数据行数
                    ReportProgress(CountProgressValue(sti, j, PageType), sti.Index, _CheckedCurrent, CountTotalSpareTime(j), hdti.RecordTime)
                    Continue For
                End If

                Array.Copy(bytes, curOffset + 6, byteSingle, 0, 4)
                hdti.AI1 = NumericConvert.Byte2Single(byteSingle)

                If _pi.ProjectType = ProjectType_Enum.Car Then
                    Array.Copy(bytes, curOffset + 10, byteSingle, 0, 4)
                    hdti.AI2 = NumericConvert.Byte2Single(byteSingle)

                    Array.Copy(bytes, curOffset + 14, byteSingle, 0, 4)
                    hdti.AI3 = NumericConvert.Byte2Single(byteSingle)

                    Array.Copy(bytes, curOffset + 18, byteSingle, 0, 4)
                    hdti.AI4 = NumericConvert.Byte2Single(byteSingle)
                End If

                Array.Copy(bytes, curOffset + 22, byteSingle, 0, 4)
                hdti.Longitude = NumericConvert.Byte2Single(byteSingle)
                hdti.Longitude_Dir = IIf((bytes(curOffset + 30) & 2) = 0, LONGITUDETYPE.East, LONGITUDETYPE.West)

                Array.Copy(bytes, curOffset + 26, byteSingle, 0, 4)
                hdti.Latitude = NumericConvert.Byte2Single(byteSingle)
                hdti.Latitude_Dir = IIf((bytes(curOffset + 30) & 1) = 0, LATITUDETYPE.South, LATITUDETYPE.North)

                '纪录该启停纪录数据上传状态
                sti.LastPageIndex = PageIndex
                sti.LastRecordTime = hdti.RecordTime
                sti.LastPageType = PageType
                sti.UploadStatus = StartUploadStatus.NotFinished
                _sts.UpdateStartUpTypeItem(sti.ID, sti.UploadStatus, sti.LastRecordTime, sti.LastPageIndex, sti.LastPageType)

                result.CurrentRecordTime = hdti.RecordTime

                '保存数据至表
                If hdts.InsertHDataTypeItem(hdti) = False Then
                    Return False
                End If

            End If

            '报告进度: 精确到数据行数
            ReportProgress(CountProgressValue(sti, j, PageType), sti.Index, _CheckedCurrent, CountTotalSpareTime(j), sti.LastRecordTime)

        Next j

        Return True
    End Function

    '计算某个启停纪录上传进度
    Private Function CountProgressValue(ByVal sti As StartUpTypeItem4DU) As Integer

        Dim totalProgress As Integer = (sti.PageCount * (_HData_HalfUp_Count + _HData_HalfDown_Count))

        If totalProgress > 0 Then
            Return (Math.Max(sti.LastPageIndex - sti.PageIndex, 0) * (_HData_HalfUp_Count + _HData_HalfDown_Count)) / totalProgress * 100
        Else
            Return 0
        End If

    End Function
    Private Function CountProgressValue(ByVal sti As StartUpTypeItem4DU, ByVal j As Integer, ByVal pageType As StartUploadPageType) As Integer

        Dim totalProgress As Integer
        totalProgress = (sti.PageCount * (_HData_HalfUp_Count + _HData_HalfDown_Count))

        '报告进度: 精确到数据行数
        If pageType = StartUploadPageType.HalfUp Then
            Return (Math.Max(sti.LastPageIndex - sti.PageIndex, 0) * (_HData_HalfUp_Count + _HData_HalfDown_Count) + j) / totalProgress * 100
        Else
            Return (Math.Max(sti.LastPageIndex - sti.PageIndex, 0) * (_HData_HalfUp_Count + _HData_HalfDown_Count) + _HData_HalfUp_Count + j) / totalProgress * 100
        End If

    End Function

    '计算上传总共剩余时间
    Private Function CountTotalSpareTime(ByVal j As Integer) As Long

        Return ((_TotalPageCount - _CurrentPageCount) * (_HData_HalfUp_Count + _HData_HalfDown_Count) + j) * UPLOAD_BASETIME

    End Function

    '检查是否构选启停纪录并选择计数与总页数统计
    Private Function CheckChecked() As Boolean
        Dim ret As Boolean = False
        Dim sti As StartUpTypeItem4DU
        _CheckedCount = 0 : _TotalPageCount = 0
        For i As Integer = 0 To _StartupList.Count - 1
            sti = _StartupList(i)
            If sti.CheckState = CheckState.Checked Then
                ret = True
                _CheckedCount += 1
                _TotalPageCount += (sti.PageCount - (sti.LastPageIndex - sti.PageIndex))
            End If
        Next i
        Return ret
    End Function

#Region " 线程安全 "

    '设置上传完成消息提示
    Private Sub SetUploadCompleted(ByVal txt As String)
        If Me.InvokeRequired Then
            Me.Invoke(New Action(Of Object)(AddressOf _SetUploadCompleted), txt)
        Else
            _SetUploadCompleted(txt)
        End If
    End Sub
    Private Sub _SetUploadCompleted(ByVal obj As Object)

        msg.Show(obj)
        Me.btnCancel.Enabled = False
        Me.btnUpload.Enabled = True

    End Sub

    '报告上传进度
    Private Sub ReportProgress(ByVal value As Integer, ByVal index As Integer, ByVal checkedSeqNo As Integer, ByVal spareTicks As Long, ByVal recordTime As DateTime)
        ReportChildProgress(value, index)
        ReportTotalProgress(value, checkedSeqNo)
        ReportTotalSpareTime(spareTicks)
        ReportRecordTime(recordTime)
    End Sub

    '报告上传子进度
    Private Sub ReportChildProgress(ByVal value As Integer, ByVal index As Integer)
        Dim obj(1) As Object
        obj(0) = value
        obj(1) = index

        If Me.InvokeRequired Then
            Me.Invoke(New Action(Of Object)(AddressOf ReportChildProgressMethod), CType(obj, Object))
        Else
            ReportChildProgressMethod(CType(obj, Object))
        End If
    End Sub
    Private Sub ReportChildProgressMethod(ByVal obj As Object)
        Dim value As Integer = obj(0)
        Dim index As Integer = obj(1)

        If index >= 0 AndAlso index < Me.bsStartup.Count Then
            Dim row As DataGridViewRow
            row = Me.dgvStartup.Rows(index)
            If row IsNot Nothing Then
                row.Cells("dProgressBar").Value = value
            End If
        End If

    End Sub

    '报告上传总进度
    Private Sub ReportTotalProgress(ByVal value As Integer, ByVal checkedSeqNo As Integer)
        Dim obj(1) As Object
        obj(0) = value
        obj(1) = checkedSeqNo

        If Me.InvokeRequired Then
            Me.Invoke(New Action(Of Object)(AddressOf ReportTotalProgressMethod), CType(obj, Object))
        Else
            ReportTotalProgressMethod(CType(obj, Object))
        End If
    End Sub
    Private Sub ReportTotalProgressMethod(ByVal obj As Object)
        Dim value As Integer = obj(0)
        Dim checkedSeqNo As Integer = obj(1)
        Dim totalProgress As Integer = ((checkedSeqNo * 100) + value) / (_CheckedCount * 100) * 100

        Me.labTotalProgress.Text = String.Format("{0}%", totalProgress)
        Me.bgUploadData.ReportProgress(totalProgress)
    End Sub

    '报告总剩余时间
    Private Sub ReportTotalSpareTime(ByVal spareTicks As Long)
        If Me.InvokeRequired Then
            Me.Invoke(New Action(Of Long)(AddressOf _ReportTotalSpareTime), spareTicks)
        Else
            _ReportTotalSpareTime(spareTicks)
        End If
    End Sub
    Private Sub _ReportTotalSpareTime(ByVal spareTicks As Long)
        If spareTicks >= 0 Then
            Dim spareTime As TimeSpan
            spareTime = New TimeSpan(spareTicks) '(_TotalPageCount - _CurrentPageCount) * UPLOAD_BASETIME
            Me.labSpareTime.Text = String.Format("{0:D2}:{1:D2}:{2:D2}", spareTime.Hours, spareTime.Minutes, spareTime.Seconds)
        End If
    End Sub

    '报告当前上传数据的纪录时间
    Private Sub ReportRecordTime(ByVal dt As DateTime)
        If Me.InvokeRequired Then
            Me.Invoke(New Action(Of DateTime)(AddressOf _ReportRecordTime), dt)
        Else
            _ReportRecordTime(dt)
        End If
    End Sub
    Private Sub _ReportRecordTime(ByVal dt As DateTime)
        If dt <> Nothing Then
            Me.labRecordTime.Text = dt.ToString()
        Else
            Me.labRecordTime.Text = String.Empty
        End If
    End Sub

    '设置上传按钮激活
    Private Sub SetUploadButtonEnabled(ByVal flag As Boolean)
        If Me.InvokeRequired Then
            Me.Invoke(New Action(Of Boolean)(AddressOf _SetUploadButtonEnabled), flag)
        Else
            _SetUploadButtonEnabled(flag)
        End If
    End Sub
    Private Sub _SetUploadButtonEnabled(ByVal flag As Boolean)
        Me.btnUpload.Enabled = flag
    End Sub

    '设置取消按钮激活
    Private Sub SetCancelButtonEnabled(ByVal flag As Boolean)
        If Me.InvokeRequired Then
            Me.Invoke(New Action(Of Boolean)(AddressOf _SetCancelButtonEnabled), flag)
        Else
            _SetCancelButtonEnabled(flag)
        End If
    End Sub
    Private Sub _SetCancelButtonEnabled(ByVal flag As Boolean)
        Me.btnCancel.Enabled = flag
    End Sub

#End Region

    '上传结果类型
    Private Class DataUploadResult

        Public CurrentRowIndex As Integer               '当前上传纪录行索引
        Public CurrentStartup As StartUpTypeItem4DU     '当前上传纪录对象
        Public CurrentPageIndex As Integer              '当前上传纪录起始页索引
        Public CurrentPageCount As Integer              '当前上传纪录总页数
        Public CurrentPageType As StartUploadPageType   '当前上传纪录起始页类型
        Public CurrentRecordTime As DateTime            '当前上传纪录页中行级数据纪录时间

        Public IsCompleted As Boolean                   '是否完成上传(单个纪录)
        Public IsCanceled As Boolean                    '是否用户取消
        Public IsChecked As Boolean                     '是否有选择上传
        Public IsError As Boolean                       '是否上传错误

    End Class

#End Region

#Region " 工具栏操作 "

    Private Sub tsbInsert_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tsbInsert.Click, tsmiInsert.Click

    End Sub

    Private Sub tsbDelete_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tsbDelete.Click, tsmiDelete.Click

    End Sub

    Private Sub tsbEdit_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tsbEdit.Click, tsmiEdit.Click

        'Edit()

    End Sub

    Private Sub tsbSave_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tsbSave.Click

        'If CheckChecked() = False Then
        '    msg.Show("未选择启停纪录。")
        '    Exit Sub
        'End If

        If Save() = True Then
            msg.Show("保存成功。")
        Else
            msg.ShowError("保存失败。")
        End If

    End Sub

    Private Sub tsbDetail_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tsbDetail.Click, tsmiDetail.Click

        Detail()

    End Sub

    Private Sub tsbHisData_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tsbHisData.Click, tsmiHisData.Click

        HistoryData()

    End Sub

    Private _isModify As Boolean '是否修改启停纪录与详细启停纪录标志
    Private _isCreate As Boolean '是否新建启停纪录

    '编辑选定启停纪录字段值
    Private Sub Edit()
        Dim sti As StartUpTypeItem4DU '(StartUpTypeBase)
        sti = Me.bsStartup.Current

        If sti IsNot Nothing AndAlso (sti.IsLoadTerminalData OrElse sti.IsLoadLocalData) Then
            Dim frm As New StartupItemForm(ActiveType.Modify, sti)
            If frm.ShowDialog() = Windows.Forms.DialogResult.OK Then
                _isModify = True
                sti.IsModifyStatup = True
            Else
                sti.IsModifyStatup = False
            End If
        End If
    End Sub

    '保存启停纪录与详细启停纪录
    Private Function Save() As Boolean

        If _sts IsNot Nothing Then

            Dim sti As StartUpTypeItem4DU

            '更新启停纪录表
            For i As Integer = 0 To _StartupList.Count - 1
                sti = _StartupList(i)

                'If sti.CheckState <> CheckState.Checked AndAlso Not sti.IsModifyStatup AndAlso Not sti.IsModifyStatupDetail Then
                '    Continue For
                'End If


                '对无停止时间或记录错误的数据不进行启停记录的保存
                If sti.UploadStatus = StartUploadStatus.NotStop Or sti.UploadStatus = StartUploadStatus.Error Then
                    Continue For
                End If

                '插入新启停纪录; (默认不管是否构选，都保存启停纪录)
                If sti.IsNewStartup = True Then
                    If _sts.InsertStartUpTypeItem(sti) = True Then '加入新启停记录时，会获取其ID
                        sti.IsNewStartup = False
                        sti.IsLoadLocalData = True
                    End If
                ElseIf sti.IsModifyStatup = True Then
                    If _sts.UpdateStartUpTypeItem(sti) = True Then
                        sti.IsModifyStatup = False
                    End If
                End If

                '更新详细启停纪录; 判断是否已经读取终端(或本地)启停纪录
                If sti.IsModifyStatupDetail = True Then
                    Dim sdts As New StartUpDetailTypeService(_pi, sti)
                    If sdts.UpdateStartUpDetailGroupList(Of StartUpDetailTypeItem4DU)(sti.DetailItemList) = True Then
                        sti.IsModifyStatupDetail = False
                    End If
                End If
            Next i

            _isModify = False
            _isCreate = False
            Return True
        End If

        Return False
    End Function

    '查看编辑选定启停纪录的详细启停纪录
    Private Sub Detail()
        Dim sti As StartUpTypeItem4DU
        sti = Me.bsStartup.Current

        '对无停止时间或记录错误的数据不显示详细启停记录
        If sti.UploadStatus = StartUploadStatus.NotStop Or sti.UploadStatus = StartUploadStatus.Error Then
            Exit Sub
        End If

        If sti IsNot Nothing AndAlso (sti.IsLoadTerminalData OrElse sti.IsLoadLocalData) Then
            Dim frm As New StartupDetailViewForm4DU(_pi, sti)
            frm.ShowDialog()
            If frm.IsModifyDetail = True Then
                _isModify = True
                sti.IsModifyStatupDetail = True
            Else
                'sti.IsModifyStatupDetail = False
            End If
        End If
    End Sub

    '查看选定启停纪录的历史数据
    Private Sub HistoryData()
        Dim sti As StartUpTypeItem4DU
        sti = Me.bsStartup.Current

        '对无停止时间或记录错误的数据不显示历史数据
        If sti.UploadStatus = StartUploadStatus.NotStop Or sti.UploadStatus = StartUploadStatus.Error Then
            Exit Sub
        End If

        If sti IsNot Nothing AndAlso (sti.IsLoadTerminalData OrElse sti.IsLoadLocalData) Then
            Dim frm As New HDViewForm(_pi, sti)
            frm.Show(Me)
        End If
    End Sub

#End Region

End Class